﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security;
using QuickTweet.Properties;
using System.Security.Cryptography;
using System.Runtime.InteropServices;
using System.Xml.Linq;
using QuickTweet.Models;
using System.Collections.ObjectModel;

namespace QuickTweet
{
    public class AppSettings
    {
        #region Crypt/Decrypt data

        static byte[] entropy = Encoding.Unicode.GetBytes("bvio tgg8dfg9'gdf nwtjgfdg89'ge0'345 nm, bnmbdfbifyt760b780bgbg98b9'+ 542 .-,.-,.dfds09895'4525t9r08gf9b'v f0d0gf8dg0f 03589't89rg7f54asdxzciuyopqeòàùpopè,ùopo'90'o+m,dasupoèàl+èp+");

        #region Examples

        //string str = "Marco";

        ////Cifra la stringa.
        //string enc = AppSettings.EncryptString(str);

        ////Trasforma la stringa cifrata in SecureString (per il salvataggio in oggetti locali).
        //System.Security.SecureString sec = AppSettings.ToSecureString(enc);

        ////Estrae la stringa dalla SecureString e la decripta.
        //var decode = AppSettings.DecryptString(sec);

        #endregion

        /// <summary>
        /// Encrypts a string to save in a secure manner.
        /// </summary>
        /// <param name="input">The string to encrypt.</param>
        /// <returns>The encrypted string.</returns>
        public static string EncryptString(string input)
        {
            return EncryptString(ToSecureString(input));
        }

        public static string EncryptString(System.Security.SecureString input)
        {
            byte[] encryptedData = ProtectedData.Protect(
                Encoding.Unicode.GetBytes(ToInsecureString(input)),
                entropy,
                DataProtectionScope.CurrentUser);
            return Convert.ToBase64String(encryptedData);
        }

        public static SecureString DecryptString(string encryptedData)
        {
            try
            {
                byte[] decryptedData = ProtectedData.Unprotect(
                    Convert.FromBase64String(encryptedData),
                    entropy,
                    DataProtectionScope.CurrentUser);
                return ToSecureString(Encoding.Unicode.GetString(decryptedData));
            }
            catch
            {
                return new SecureString();
            }
        }

        /// <summary>
        /// Decrypts a SecureString and returns its plain text.
        /// </summary>
        /// <param name="input">The SecureString.</param>
        /// <returns>The plain text.</returns>
        public static string DecryptString(SecureString input)
        {
            return ToInsecureString(DecryptString(ToInsecureString(input)));
        }

        /// <summary>
        /// Creates a SecureString from a plain text.
        /// </summary>
        /// <param name="input">The string with which to build the SecureString.</param>
        /// <returns>The SecureString.</returns>
        public static SecureString ToSecureString(string input)
        {
            SecureString secure = new SecureString();
            foreach (char c in input)
                secure.AppendChar(c);

            secure.MakeReadOnly();
            return secure;
        }

        public static string ToInsecureString(SecureString input)
        {
            string returnValue = string.Empty;
            IntPtr ptr = Marshal.SecureStringToBSTR(input);
            try
            {
                returnValue = Marshal.PtrToStringBSTR(ptr);
            }
            finally
            {
                Marshal.ZeroFreeBSTR(ptr);
            }
            return returnValue;
        }

        #endregion

        #region Properties

        public static string ConsumerKey
        {
            get { return Constants.CONSUMER_KEY; }
        }

        public static string ConsumerSecret
        {
            get { return Constants.CONSUMER_SECRET; }
        }

        private static List<TwitterAccount> twitterAccounts;
        public static List<TwitterAccount> TwitterAccounts
        {
            get
            {
                return twitterAccounts;
            }
            set
            {
                twitterAccounts = value;
            }
        }

        #endregion

        private const string SETTINGS_FILE = "Settings.xml";

        static AppSettings()
        {
            LoadAccounts();
        }

        private static void LoadAccounts()
        {
            //Legge gli account correnti.
            XDocument settingsFile = XDocument.Load(SETTINGS_FILE);
            var accountNodes = from account in settingsFile.Descendants("Account")
                               where account.Attribute("Name") != null && !string.IsNullOrWhiteSpace(account.Attribute("Name").Value)
                               && account.Attribute("TwitterID") != null && !string.IsNullOrWhiteSpace(account.Attribute("TwitterID").Value)
                               && account.Attribute("AccessToken") != null && !string.IsNullOrWhiteSpace(account.Attribute("AccessToken").Value)
                               && account.Attribute("AccessTokenSecret") != null && !string.IsNullOrWhiteSpace(account.Attribute("AccessTokenSecret").Value)
                               select account;

            List<TwitterAccount> accounts = new List<TwitterAccount>();
            foreach (var account in accountNodes)
            {
                var twitterAccount = new TwitterAccount { Name = account.Attribute("Name").Value, TwitterID = account.Attribute("TwitterID").Value };
                int order;
                int.TryParse(account.Attribute("Order").Value, out order);
                twitterAccount.Order = order;

                try
                {
                    twitterAccount.AccessToken = AppSettings.ToSecureString(account.Attribute("AccessToken").Value);
                }
                catch { }

                try
                {
                    twitterAccount.AccessTokenSecret = AppSettings.ToSecureString(account.Attribute("AccessTokenSecret").Value);
                }
                catch { }

                accounts.Add(twitterAccount);
            }

            twitterAccounts = new List<TwitterAccount>(accounts.OrderBy(a => a.Order).ThenBy(a => a.Name));
        }

        public static void Save()
        {
            var doc = new XDocument(
            new XDeclaration("1.0", "utf-8", null),
                new XElement("Settings",
                    new XElement("TwitterAccounts",
                    twitterAccounts.Select(acc => new XElement("Account", new XAttribute("Name", acc.Name),
                        new XAttribute("TwitterID", acc.TwitterID), new XAttribute("AccessToken", AppSettings.ToInsecureString(acc.AccessToken)),
                        new XAttribute("AccessTokenSecret", AppSettings.ToInsecureString(acc.AccessTokenSecret)),
                        new XAttribute("Order", acc.Order)
                            )
                        )
                    )
                )
            );

            doc.Save(SETTINGS_FILE);
        }
    }
}
